package com.googlecode.imanager.jasper;

import net.sf.jasperreports.engine.JRDefaultStyleProvider;
import net.sf.jasperreports.engine.JRPrintElement;

import com.googlecode.imanager.client.Container;
import com.googlecode.imanager.client.Control;
import com.googlecode.imanager.client.Manager;
import com.googlecode.imanager.client.action.Action;
import com.googlecode.imanager.client.bridge.IControl;
import com.googlecode.imanager.client.exception.BridgeException;
import com.googlecode.imanager.client.style.Style;
import com.googlecode.imanager.client.style.listener.StyleAttribute;
import com.googlecode.imanager.client.style.listener.StyleWrapper;
import com.googlecode.imanager.core.base.AbstractControl;
import com.googlecode.imanager.core.base.BridgeApplication;
import com.googlecode.imanager.core.base.style.ComputedTheme;
import com.googlecode.imanager.jasper.print.RChild;
import com.googlecode.imanager.jasper.print.RFrame;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public abstract class RControl extends AbstractControl implements IControl {

    protected StyleWrapper styleWrapper;
    protected RFrame parentFrame;
    protected RChild target;
    protected boolean printing;
    protected boolean refactoring;
    
    public RControl(BridgeApplication bridge, Control source) {
        super(bridge, source);
        this.target = createTarget();
    }
    
    protected void initImplementation() {
        doInitialAssignment();
        doParseStyle();
        // TODO allocated them impl Manager.lookupThemeImpl(control, scope)
    }

    private void doParseStyle() {
        // TODO Auto-generated method stub
        
    }

    @Override
    protected void start() {
        initImplementation();
        super.start();
    }

    @Override
    protected void destroy() {
        if (parentFrame != null){
            parentFrame.getElements().remove(target);
            parentFrame = null;
        }
        target.destroy();
        super.destroy();
    }

    protected abstract RChild createTarget();

    public abstract void setDefaultStyleProvider(JRDefaultStyleProvider defaultStyleProvider);
    
    @Override
    public RChild getTarget() {
        return target;
    }
    
    public JRPrintElement cloneTarget(){
        
        // O objetivo deste metodo é clonar o objeto target, 
        // voltar o original como retorno do método
        // e por a cópia feita no campo "target" desta classe.
        //
        // O trecho abaixo é um workaround porque JRBasePrintElement não é Cloneable.
        
        RChild old = target;
        assert (!refactoring);
        
        refactoring = true;
        try {
            /*if (oldParent != null){
                oldParent.getElements().remove(target);
                oldParent = null;
            }*/
            
            target = createTarget();
            initImplementation();
        } finally {
            refactoring = false;
        }
    
        if (printing){
            target.setX(old.getX());
            target.setY(old.getY());
            target.setWidth(old.getWidth());
            target.setHeight(old.getHeight());
        }

        return old;
    }

    public RFrame getParentFrame() {
        return parentFrame;
    }

    public void setParentFrame(RFrame parentFrame) {
        this.parentFrame = parentFrame;
    }

    public boolean isPrinting() {
        return printing;
    }

    public void setPrinting(boolean printing) {
        this.printing = printing;
    }

    @Override
    public ComputedTheme getComputedTheme() {
        return getParentComputedTheme();
    }

    @Override
    @SuppressWarnings("unchecked")
    public void setParent(Container parent) {
        if (refactoring){
            return;
        }
        
        if (parentFrame != null){
            parentFrame.getElements().remove(target);
            parentFrame = null;
        }
                
        if (parent != null){
            parentFrame = ((RContainer) Manager.getImpl(parent)).getTarget();
            parentFrame.getElements().add(target);
        }
        
        if (printing){
            throw new BridgeException("cannot change control hierarchy while building Jasper implementation");
        }
    }

    @Override
    public void click() {
        // nothing to do
    }

    @Override
    public void realign() {
        // nothing to do
    }

    @Override
    public void refresh() {
        // nothing to do
    }

    @Override
    public void scrollToRectVisible(int left, int top, int width, int height) {
        // nothing to do
    }

    @Override
    public void setAction(Action action) {
        // nothing to do
    }

    @Override
    public void setBounds(int left, int top, int width, int height) {
        if (!printing){
            target.setX(left);
            target.setY(top);
            target.setWidth(width);
            target.setHeight(height);
        }
    }

    @Override
    public void setDisabled(Boolean disabled) {
        // nothing to do
    }

    @Override
    public void setHint(String hint) {
        // nothing to do
    }

    @Override
    public void setStyle(Style style) {
        // TODO Auto-generated method stub
    }

    @Override
    public void setVisible(Boolean visible) {
        target.setVisible(Boolean.TRUE.equals(visible));
    }

    @Override
    protected <T> void doComputeStyle(StyleAttribute<T> attribute) {
        // TODO Auto-generated method stub
        super.doComputeStyle(attribute);
    }

}
